home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
pcr
/
pcr4_4.lha
/
DIST
/
threads
/
ThreadsTests2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-11-30
|
10KB
|
401 lines
/* begincopyright
Copyright (c) 1988 Xerox Corporation. All rights reserved.
Use and copying of this software and preparation of derivative works based
upon this software are permitted. Any distribution of this software or
derivative works must comply with all applicable United States export
control laws. This software is made available AS IS, and Xerox Corporation
makes no warranty about the software, its performance or its conformity to
any specification. Any person obtaining a copy of this software is requested
to send their name and post office or electronic mail address to:
PCR Coordinator
Xerox PARC
3333 Coyote Hill Rd.
Palo Alto, CA 94304
endcopyright */
/*
* ThreadsTests2.c
*
* Demers, November 30, 1989 7:29:16 pm PST
*
* Regression tests for gc under threads.
*/
#include "xr/Errno.h"
#include "xr/ThreadsBackdoor.h"
#include "xr/GC.h"
#include "xr/Threads.h"
#ifndef _TIME_
#include <sys/time.h>
#endif
typedef XR_FinalizationHandle Handle;
extern XR_FinalizationQueue XR_NewFQ();
extern Handle XR_NewFinalizationHandle();
extern Handle XR_FQNextNoAbort();
/*
* Parameters
*/
int TF_gcInterval = 50; /* NEWs between forced collections */
int TF_nHeaders = 50; /* number of pointers held to objects */
int TF_iterations = 10000; /* number of iterations to run test */
/*
* statistics data structure
*/
typedef struct TF_FinalizationStatsRep {
int fstats_addedToCache;
int fstats_droppedFromCache;
int fstats_dequeued;
int fstats_resurrected;
} * TF_FinalizationStats;
static void
TF_PrintStats(i, fstats)
int i;
TF_FinalizationStats fstats;
{
XR_ConsoleMsg("Iter %d: ", i);
XR_ConsoleMsg("add %d, ", fstats->fstats_addedToCache);
XR_ConsoleMsg("drop %d, ", fstats->fstats_droppedFromCache);
XR_ConsoleMsg("dequeue %d, ", fstats->fstats_dequeued);
XR_ConsoleMsg("resurrect %d\n", fstats->fstats_resurrected);
}
/*
* This is a MONITOR!
*/
static struct XR_MLRep TF_lock;
/*
* The global finalization queue
*/
static XR_FinalizationQueue TF_fq = NIL;
/*
* Failure message printer
*/
static void
TF_Fail(msg, x1, x2, x3, x4)
char *msg;
int x1, x2, x3, x4;
{
XR_ConsoleMsg("Finalization test failed: ");
XR_ConsoleMsg(msg, x1, x2, x3, x4);
XR_ConsoleMsg("\n");
XR_TestFailed("oops!");
/*NOTREACHED*/
}
/*
* Random numbers
*/
extern bool CoinToss();
extern unsigned RandomInRange();
#define TF_Random(range) RandomInRange(range)
#define TF_CoinToss() CoinToss()
/*
* Objects
*/
typedef struct TFObj {
int tfo_refCnt;
int tfo_enabledCnt;
int tfo_finalizedCnt;
Handle tfo_hNext;
Handle tfo_hPrev;
struct TFObj * tfo_pChild;
struct TFObj * tfo_pSibling;
};
static void
TF_InitObj (tfo)
struct TFObj *tfo;
{
tfo->tfo_refCnt = 0;
tfo->tfo_enabledCnt = 0;
tfo->tfo_finalizedCnt = 0;
tfo->tfo_hNext = NIL;
tfo->tfo_hPrev = NIL;
tfo->tfo_pChild = NIL;
tfo->tfo_pSibling = NIL;
}
/*
* Allocation
*
* Doesn't need to be ENTRY because it's okay for numNewCalls to be approximate.
*/
static unsigned TF_numNewCalls = 0;
static struct TFObj *
TF_NewObj ()
{
struct TFObj *tfo = (struct TFObj *)XR_malloc(sizeof(struct TFObj));
TF_InitObj(tfo);
if( ((++TF_numNewCalls) % TF_gcInterval) == 0 ) XR_GCollect();
return tfo;
}
/*
* Object cache
*
* Note the cache contains every object, not every tree of objects.
*/
static Handle TF_cache = NIL;
static void
TF_AddToCache(h, fstats)
Handle h;
TF_FinalizationStats fstats;
{
struct TFObj *self;
Handle hNext;
struct TFObj *next;
Handle hPrev;
struct TFObj *prev;
XR_MonitorEntry(&TF_lock);
self = (struct TFObj *) XR_HandleToObject(h);
if( TF_cache == NIL ) {
self->tfo_hNext = self->tfo_hPrev = h;
} else {
hNext = TF_cache;
next = (struct TFObj *) XR_HandleToObject(hNext);
hPrev = next->tfo_hPrev;
prev = (struct TFObj *) XR_HandleToObject(hPrev);
self->tfo_hNext = hNext;
self->tfo_hPrev = hPrev;
next->tfo_hPrev = h;
prev->tfo_hNext = h;
}
TF_cache = h;
fstats->fstats_addedToCache += 1;
XR_MonitorExit(&TF_lock);
}
static void
TF_RemoveFromCache(h, fstats)
Handle h;
TF_FinalizationStats fstats;
{
struct TFObj *self;
Handle hNext;
struct TFObj *next;
Handle hPrev;
struct TFObj *prev;
XR_MonitorEntry(&TF_lock);
self = (struct TFObj *) XR_HandleToObject(h);
hNext = self->tfo_hNext;
hPrev = self->tfo_hPrev;
if( (hNext == NIL) || (hPrev == NIL) ) TF_Fail("RemoveFromCache botch 1");
next = (struct TFObj *) XR_HandleToObject(hNext);
prev = (struct TFObj *) XR_HandleToObject(hPrev);
if( (next == NIL) || (prev == NIL) ) TF_Fail("RemoveFromCache botch 2");
self->tfo_hNext = self->tfo_hPrev = NIL;
if( next != self ) {
prev->tfo_hNext = hNext;
next->tfo_hPrev = hPrev;
TF_cache = hNext;
} else {
TF_cache = NIL;
}
fstats->fstats_droppedFromCache += 1;
XR_MonitorExit(&TF_lock);
}
/*
* Table of REFs to remembered objects
*/
static struct TFObj **TF_remembered = NIL;
static void
TF_InitRemembered()
{
int i;
TF_remembered =
(struct TFObj **) XR_malloc(TF_nHeaders * sizeof( struct TFObj *));
for( i = 0; i < TF_nHeaders; i++ ) TF_remembered[i] = NIL;
}
static void
TF_Remember(tfo)
struct TFObj * tfo;
{
struct TFObj * old;
unsigned i;
XR_MonitorEntry(&TF_lock);
if( TF_remembered == NIL ) TF_InitRemembered();
i = TF_Random(TF_nHeaders);
old = TF_remembered[i];
TF_remembered[i] = tfo;
tfo->tfo_refCnt += 1;
if( old != NIL ) old->tfo_refCnt -= 1;
XR_MonitorExit(&TF_lock);
}
static void
TF_ForgetAll()
{
struct TFObj * tfo;
unsigned i;
XR_MonitorEntry(&TF_lock);
if( TF_remembered != NIL ) {
for( i = 0; i < TF_nHeaders; i++ ) {
if( (tfo = TF_remembered[i]) != NIL ) {
tfo->tfo_refCnt -= 1;
TF_remembered[i] = NIL;
}
}
TF_remembered = NIL;
}
XR_MonitorExit(&TF_lock);
}
/*
* Create random tree
*
* Result is finalizable and in cache.
* It has not been remembered, so its ref cnt is 0, but children's ref counts are nonzero.
*/
static struct TFObj *
TF_CreateTree(depth, fstats)
int depth;
TF_FinalizationStats fstats;
{
struct TFObj * root;
struct TFObj * child;
Handle h;
int nChildren;
root = TF_NewObj();
if( depth >= 3 ) return root;
for( nChildren = 0; nChildren < 3; nChildren++ ) {
if( TF_CoinToss() ) break;
}
for( ; nChildren > 0; nChildren-- ) {
child = TF_CreateTree(depth+1, fstats);
child->tfo_pSibling = root->tfo_pChild;
root->tfo_pChild = child;
child->tfo_refCnt += 1;
}
h = XR_NewFinalizationHandle();
root->tfo_enabledCnt += 1;
XR_EnableFinalization(root, TF_fq, h);
TF_AddToCache(h, fstats);
return root;
}
static unsigned
TF_Finalizer(self)
XR_MesaProc self;
{
Handle h;
struct TFObj * tfo;
XR_FinalizationState oldState;
TF_FinalizationStats fstats;
fstats = (TF_FinalizationStats)(self->mp_x);
for(;;) {
h = XR_FQNextNoAbort(TF_fq);
if( h == NIL ) return; /* finalizer aborted */
fstats->fstats_dequeued += 1;
tfo = (struct TFObj *) XR_HandleToObject(h);
if( tfo == NIL ) TF_Fail("NIL obj h 0x%x tfo 0x%x", h, tfo);
if( tfo->tfo_enabledCnt != (tfo->tfo_finalizedCnt+1) )
TF_Fail("enabledCnt botch ec %d fc %d", tfo->tfo_enabledCnt, tfo->tfo_finalizedCnt);
if( tfo->tfo_refCnt != 0 )
TF_Fail("refCnt botch rc %d", tfo->tfo_refCnt);
tfo->tfo_finalizedCnt += 1;
if( TF_CoinToss() ) {
/* resurrect the object */
oldState = XR_ReenableFinalization(h, TF_fq);
if( oldState != fzsDisabled )
TF_Fail("re-enable oldState botch os %d", oldState);
tfo->tfo_enabledCnt += 1;
TF_Remember(tfo);
fstats->fstats_resurrected += 1;
} else {
/* drop the object */
if( tfo->tfo_pChild != NIL )
tfo->tfo_pChild->tfo_refCnt -= 1;
tfo->tfo_pChild = NIL;
if( tfo->tfo_pSibling != NIL )
tfo->tfo_pSibling->tfo_refCnt -= 1;
tfo->tfo_pSibling = NIL;
TF_RemoveFromCache(h, fstats);
}
}
}
void
TestFinalizationWorker()
{
int i;
XR_MesaProc mp;
struct XR_CTRep child;
TF_FinalizationStats fstats;
TF_fq = XR_NewFQ ();
fstats = (TF_FinalizationStats)
XR_calloc( sizeof(struct TF_FinalizationStatsRep), 1);
XR_ConsoleMsg("Creating finalizer ... ");
mp = XR_MakeMesaProc(TF_Finalizer, fstats);
XR_Fork(&child, mp);
(void)XR_DetachCT(&child);
XR_ConsoleMsg("ok\n");
XR_ConsoleMsg("Starting %d iterations ...\n", TF_iterations);
for( i = 0; i < TF_iterations; i++ ) {
struct TFObj * randomTree;
if( (i % 1000) == 0 ) TF_PrintStats(i, fstats);
randomTree = TF_CreateTree(0, fstats);
TF_Remember(randomTree);
}
TF_ForgetAll();
for( i = 0; ; i++) {
if( TF_cache == NIL ) break;
if( i >= 20 ) break;
XR_GCollect();
XR_PauseAbortable(XR_MsecToTicks(1000));
}
XR_ConsoleMsg("Done.\n");
}